
#ifndef _MEMBER_BOBCDOCUMENT_H_
#define _MEMBER_BOBCDOCUMENT_H_

#include <BMap>
#include <BScene>
#include <BMesh>
#include <BCone>
#include <BCube>
#include <BCylinder>
#include <BSphere>
#include <BGeoSphere>
#include <BTube>
#include <BTorus>
#include <BSurface>
#include <BTerrain>
#include <BTextual>
#include <BBillboard>
#include <BParticle>
#include <BCapsule>
#include <BPointConstraint>
#include <BHingeConstraint>
#include <BSliderConstraint>
#include <BConearConstraint>
#include <BSixdofConstraint>

#include <BImage>
#include <BFont>
#include <BStyle>
#include <BPixmap>
#include <BMaterial>
#include <BProgram>
#include <BUniform>
#include <BPhysics>
#include <BScript>
#include <BSource>
#include <BSpring>
#include <BSpacer>

#include <BApplication>
#include <BFile>
#include <BBuffer>
#include <BReadWrite>
#include <BObcDocument>

#define obcdoc_member(obcdoc)		((member_BObcDocument*)((BObcDocument*)obcdoc)->_ptr)

namespace BWE
{

#pragma pack(1)
	struct Chunk
	{
		Chunk()
		{
			sign = 0;
			end = 0;
		}
		unsigned short	sign;
		unsigned int	end;
	};
#pragma pack()

	struct ChunkInfo
	{
		unsigned int		begin;
		unsigned short		sign;
		unsigned int		end;
	};

	class member_BObcDocument
	{
	public:
		member_BObcDocument(BObcDocument* obcDocument);
		~member_BObcDocument();

		void reset();

		BObject* read(const Chunk& chunk);
		bool write(const BObject* object);

		inline BString& message()
		{
			if (messageValue.empty())
				messageValue = new BString();
			BString& text = messageValue;
			return text;
		}
		inline const BString& message() const
		{
			const BString& text = messageValue;
			return text;
		}

		bool beginChunk(BUShort sign)
		{
#ifdef REAL_IS_DOUBLE
			if (sign < 50)
				sign += 50;
#endif
			ChunkInfo& cinfo = chunkStack.append();
			cinfo.sign = sign;
			cinfo.end = 0;
			cinfo.begin = stream->offset();
			stream->write(cinfo.sign);
			stream->write(cinfo.end);
			chunkLevel++;
			return true;
		}
		bool endChunk(BUShort sign)
		{
#ifdef REAL_IS_DOUBLE
			if (sign < 50)
				sign += 50;
#endif
			ChunkInfo& cinfo = chunkStack.last();
			if (cinfo.sign == sign)
			{
				cinfo.end = stream->offset();
				stream->seek(cinfo.begin);
				stream->write(cinfo.sign);
				stream->write(cinfo.end);
				stream->seek(cinfo.end);
				chunkLevel--;
				chunkStack.remove(chunkStack.size() - 1);
				return true;
			}
			return false;
		}

		bool readBeginChunk(Chunk& chunk, int end);
		bool readEndChunk(Chunk& chunk);

	public:
		typedef bool (member_BObcDocument::* readFunc)(const Chunk&, BObject*);
		typedef bool (member_BObcDocument::* writeFunc)(const BObject*);
		inline void regist(const BString& type, SIGN sign, readFunc rf, writeFunc wf)
		{
			this->readFuncMap[type] = rf;
			this->writeFuncMap[type] = wf;
			this->typeSignMap[type] = sign;
			this->signTypeMap[sign] = type;
		}

		//read chunk
		bool readObject(const Chunk& chunk, BObject* object);
		bool readScene(const Chunk& chunk, BScene* scene);
		bool readGroup(const Chunk& chunk, BGroup* group);
		bool readNode(const Chunk& chunk, BNode* node);
		bool readLight(const Chunk& chunk, BLight* light);
		bool readCamera(const Chunk& chunk, BCamera* camera);
		bool readBillboard(const Chunk& chunk, BBillboard* billboard);
		bool readConstraint(const Chunk& chunk, BConstraint* constraint);
		bool readPointConstraint(const Chunk& chunk, BPointConstraint* constraint);
		bool readHingeConstraint(const Chunk& chunk, BHingeConstraint* constraint);
		bool readSliderConstraint(const Chunk& chunk, BSliderConstraint* constraint);
		bool readConearConstraint(const Chunk& chunk, BConearConstraint* constraint);
		bool readSixdofConstraint(const Chunk& chunk, BSixdofConstraint* constraint);

		bool readShape(const Chunk& chunk, BShape* shape);
		bool readMesh(const Chunk& chunk, BMesh* mesh);
		bool readGeometry(const Chunk& chunk, BGeometry* geometry);
		bool readTextual(const Chunk& chunk, BTextual* textual);
		bool readParticle(const Chunk& chunk, BParticle* particle);
		bool readElement(const Chunk& chunk, BElement* element);

		bool readCube(const Chunk& chunk, BCube* cube);
		bool readCone(const Chunk& chunk, BCone* cone);
		bool readCylinder(const Chunk& chunk, BCylinder* cylinder);
		bool readSphere(const Chunk& chunk, BSphere* sphere);
		bool readGeoSphere(const Chunk& chunk, BGeoSphere* geoSphere);
		bool readTube(const Chunk& chunk, BTube* tube);
		bool readTorus(const Chunk& chunk, BTorus* torus);
		bool readSurface(const Chunk& chunk, BSurface* surface);
		bool readTerrain(const Chunk& chunk, BTerrain* terrain);
		bool readCapsule(const Chunk& chunk, BCapsule* capsule);

		bool readMaterial(const Chunk& chunk, BMaterial* material);
		bool readTexture(const Chunk& chunk, BTexture* texture);
		bool readImage(const Chunk& chunk, BImage* image);
		bool readPixmap(const Chunk& chunk, BPixmap* pixmap);
		bool readProgram(const Chunk& chunk, BProgram* program);
		bool readShader(const Chunk& chunk, BShader* shader);
		bool readUniform(const Chunk& chunk, BUniform* uniform);
		bool readPhysics(const Chunk& chunk, BPhysics* physics);
		bool readScript(const Chunk& chunk, BScript* script);
		bool readSource(const Chunk& chunk, BSource* source);
		bool readExp(const Chunk& chunk, BExp* exp);

		//write chunk.
		bool writeWidgetData(const BWidget* widget);

		bool writeObject(const BObject* object);
		bool writeScene(const BScene* scene);
		bool writeGroup(const BGroup* group);
		bool writeNode(const BNode* node);
		bool writeLight(const BLight* light);
		bool writeCamera(const BCamera* camera);
		bool writeBillboard(const BBillboard* billboard);
		bool writeConstraint(const BConstraint* constraint);
		bool writePointConstraint(const BPointConstraint* pointConstraint);
		bool writeHingeConstraint(const BHingeConstraint* hingeConstraint);
		bool writeSliderConstraint(const BSliderConstraint* sliderConstraint);
		bool writeConearConstraint(const BConearConstraint* conearConstraint);
		bool writeSixdofConstraint(const BSixdofConstraint* sixdofConstraint);

		bool writeShape(const BShape* shape);
		bool writeMesh(const BMesh* mesh);
		bool writeGeometry(const BGeometry* geometry);
		bool writeTextual(const BTextual* textual);
		bool writeParticle(const BParticle* particle);
		bool writeElement(const BElement* element);

		bool writeCube(const BCube* cube);
		bool writeCone(const BCone* cone);
		bool writeCylinder(const BCylinder* cylinder);
		bool writeSphere(const BSphere* sphere);
		bool writeGeoSphere(const BGeoSphere* geoSphere);
		bool writeTube(const BTube* tube);
		bool writeTorus(const BTorus* torus);
		bool writeSurface(const BSurface* surface);
		bool writeTerrain(const BTerrain* terrain);
		bool writeCapsule(const BCapsule* capsule);

		bool writeMaterial(const BMaterial* material);
		bool writeTexture(const BTexture* texture);
		bool writeImage(const BImage* image);
		bool writePixmap(const BPixmap* pixmap);
		bool writeProgram(const BProgram* program);
		bool writeShader(const BShader* shader);
		bool writeUniform(const BUniform* uniform);
		bool writePhysics(const BPhysics* physics);
		bool writeScript(const BScript* script);
		bool writeSource(const BSource* source);
		bool writeExp(const BExp* exp);

	private:
		class AutoChunk
		{
		public:
			inline AutoChunk(member_BObcDocument* obcdoc, BUShort sign)
			{
				this->obcdoc = obcdoc;
				obcdoc->beginChunk(sign);
				this->sign = obcdoc->chunkStack.last().sign;
			}
			inline ~AutoChunk()
			{
				obcdoc->endChunk(sign);
			}
			BUShort			sign;
			member_BObcDocument* obcdoc;
		};

	public:
		BObcDocument*				boss;
		BStream*					stream;
		BObjectHolder				object;
		BArray<ChunkInfo>			chunkStack;
		int							chunkLevel;
		BValue						messageValue;
		BMap<int, BObject*>			readObjectMap;
		BMap<const BObject*, int>	writeObjectMap;

		BMap<BString, BObcDocument::readChunk>		readChunkMap;
		BMap<BString, BObcDocument::writeChunk>		writeChunkMap;
		BMap<BString, readFunc>			readFuncMap;
		BMap<BString, writeFunc>		writeFuncMap;
		BMap<BString, BUShort>			typeSignMap;
		BMap<BUShort, BString>			signTypeMap;

	};

}

#endif